"""
author: liuxu
date: 2025/6/4
description: 测试pmc相关的bug
"""
import os
import allure
import pytest
import math

from common.logger_ctrl import mylogger
from common.ssh_command import exec_cmd
from common.common_func import extract_csv_data
from base_public.testbase import BasePublic
from setting import CPP_DIR


@pytest.mark.medium
@allure.feature('pmc相关bug')
class TestPmcBugCase(BasePublic):
    """测试pmc功能"""
    def test_bug_80211(self, test_env):
        """
        Bug链接: http://hpczentao.sugon.com/bug-view-80211.html
        标题: 使用 hipprof或rocprof 抓取特定的 PMC 指标数据异常
        问题描述: 驱动问题（在配置要读取的寄存器时，会先将要读取的库按block进行一次排序。将此时的顺序和用户指定的顺序进行匹配的环节有问题，导致最终读取的顺序不正确）
        :return:
        """
        # 编译用例
        src_case_dir = os.path.join(CPP_DIR, "bug_case/bug-80211")
        exe_path = self.compile_source_code("vcopy_test/vcopy.cpp")
        rocprof_exe = os.path.expandvars('$ROCM_PATH/rocprofiler/bin/rocprof')  # 展开rocprof环境变量

        # 执行roprof测试
        ret, output = exec_cmd(f"{rocprof_exe} -i {os.path.join(src_case_dir, 'pmc.txt')} {exe_path} -n 1048576 -b 256", cwd=test_env)

        # 校验结果
        assert ret is True
        assert self.exist_file(os.path.join(test_env, "pmc.csv")), "The pmc data file was not generated"
        pmc_data = extract_csv_data(file_path="./pmc.csv")[0]
        assert int(pmc_data["GRBM_GUI_ACTIVE"]) == int(pmc_data["GRBM_COUNT"]) > 0
        assert pmc_data["SQ_INSTS_LDS"] == "0"

    def test_bug_81609(self, test_env, dcu_info):
        """
        Bug链接: http://hpczentao.sugon.com/bug-view-81609.html
        标题: pmc指标中的vgpr count和sgpr count数据显示跟实际情况不符
        问题描述: pmc问题
        :return:
        """
        # 编译用例
        gfx_arch = dcu_info["gfx_arch"]
        exe_path = self.compile_source_code(src_file_name="hipSimple/matrix.cpp", compile_paras=f"--offload-arch={gfx_arch}")
        # 测试hipprof --pmc ./MatrixTranspose，观察pmc_results_pid.txt中的vgpr count和sgpr count的值
        ret0, output0 = exec_cmd(f"hipprof --pmc {exe_path}", cwd=test_env)
        assert ret0 is True
        pid = self.get_prof_pid(output0)
        pmc_file = f"pmc_results_{pid}.txt"
        assert os.path.exists(pmc_file), f"The {pmc_file} file was not generated"
        with open(pmc_file) as f:
            for line in f.readlines():
                if line.strip().startswith("vgpr count"):
                    pmc_vgpr_count = int(line.split(" ")[-1])
                elif line.strip().startswith("sgpr count"):
                    pmc_sgpr_count = int(line.split(" ")[-1])
        mylogger.debug(f"[{pmc_file}]vgpr_count: {pmc_vgpr_count}, sgpr_count: {pmc_sgpr_count}")

        # dccobjdump --inputs=MatrixTranspose,观察MatrixTranspose-gfx9*-0.ISA文件中的.sgpr_count和.vgpr_count的值
        ret1, output1 = exec_cmd(f"dccobjdump --inputs={exe_path}", cwd=test_env)
        assert ret1 is True
        isa_file = f"{os.path.basename(exe_path)}-{gfx_arch}-0.ISA"
        assert os.path.exists(isa_file), f"The {isa_file} file was not generated"
        with open(isa_file) as f:
            for line in f.readlines():
                if line.strip().startswith(".vgpr_count:"):
                    dccobjdump_vgpr_count = int(line.split(" ")[-1])
                elif line.strip().startswith(".sgpr_count:"):
                    dccobjdump_sgpr_count = int(line.split(" ")[-1])
        mylogger.debug(f"[{isa_file}]vgpr_count: {dccobjdump_vgpr_count}, sgpr_count: {dccobjdump_sgpr_count}")

        # 根据公式判断pmc生成的sgpr、vgpr数量与dccobjdump生成的数据接近（相差50%以内）
        # assert pmc_vgpr_count == (dccobjdump_vgpr_count + 1) * 4
        # assert pmc_sgpr_count == (dccobjdump_sgpr_count/2 + 1) * 16
        assert math.isclose(pmc_vgpr_count, dccobjdump_vgpr_count, rel_tol=0.5)
        assert math.isclose(pmc_sgpr_count, dccobjdump_sgpr_count, rel_tol=0.5)

    def test_bug_92260(self, test_env):
        """
        Bug链接: http://hpczentao.sugon.com/bug-view-92260.html
        标题: 【DTK-25.04.1-需求】hipprof收集PMC指标，返回数量少于配置数量
        问题描述: pmc问题
            问题原因：之前的过滤方式有误，在correct_features中仅使用id作为过滤方式，当遇到相同id指标，会将后续指标错误删除
            修改方案：使用block name及id号进行过滤，防止错误过滤
        :return:
        """
        # 编译用例
        exe_path = self.compile_source_code(src_file_name="vcopy_test/vcopy.cpp")
        with open(os.path.join(test_env, "filter.txt"), "w") as f:
            f.write("pmc: SQ_CYCLES GRBM_GUI_ACTIVE")

        exec_cmd("cat filter.txt")
        ret, output = exec_cmd(f"hipprof --pmc -i filter.txt {exe_path} -n 1048576 -b 256", cwd=test_env)
        assert ret is True
        prof_pid = self.get_prof_pid(output)
        csv_name = f"pmc_results_{prof_pid}.csv"
        pmc_data_d = extract_csv_data(file_path=csv_name)[0]
        mylogger.debug(f"{csv_name}:\npmc_data")

        # 校验这两个指标存在，且有值
        assert int(pmc_data_d.get("SQ_CYCLES", -1)) > 0
        assert int(pmc_data_d.get("GRBM_GUI_ACTIVE", -1)) > 0

    def test_bug_93877(self, test_env):
        """
        Bug链接: http://hpczentao.sugon.com/bug-view-93877.html
        标题: hipprof分析多进程程序的PMC时，无法正确导出结果
        问题描述: pmc问题
        """
        exe_path = self.compile_source_code(src_file_name="bug_case/bug-93877/TestProcesses.cpp")
        ret, output = exec_cmd(f"hipprof --pmc {exe_path}")
        assert ret is True

        # 获取生成的txt文件名
        prof_pid = self.get_prof_pid(output)
        txt_name = f"pmc_results_{prof_pid}.txt"

        kernel_l = []
        with open(os.path.join(test_env, txt_name), "r") as f:
            for line in f.readlines():
                if line.strip().startswith("kernel-name:"):
                    kernel_name = line.split("kernel-name:")[-1]
                    kernel_l.append(kernel_name)
        # 检测多进程的运行的两个kernel(sub/add)均有记录
        assert len(kernel_l) == 2
        assert "sub" in kernel_l[0] and "add" in kernel_l[1]  or ("sub" in kernel_l[1] and "add" in kernel_l[0])

    def test_bug_105745(self, test_env, dcu_info):
        """
        Bug链接: http://hpczentao.sugon.com/bug-view-105745.html
        标题: 多线程在多个设备启动核函数时，hipprof启动PMC报错
        问题描述: pmc问题
        """
        # 编译待测用例
        exe_path = self.compile_source_code(src_file_name="multiproc_case/multithreading_multidevice.cpp")

        # 执行测试命令
        ret, output = exec_cmd(f"hipprof --pmc {exe_path}")
        assert ret is True

        # 获取pmc数据
        prof_pid = self.get_prof_pid(output)
        out_pmc_file = f"pmc_results_{prof_pid}.txt"
        pmc_info_l = self.get_pmc_info_from_txt(out_pmc_file, pmc_type="basic")

        # 校验pmc生成的kernel个数，device id与可用dcu信息是否一致
        avail_device = dcu_info["devices_id"]
        pmc_gpu_ids = [kernel_data["gpu_id"] for item in pmc_info_l for kernel_data in item.values()]

        assert len(avail_device) == len(pmc_info_l)
        assert set(avail_device) == set(pmc_gpu_ids)





